--TFF: Tiny F...ast Felth. Author: notabug.org/debris/ . Fundamental macros have been added.
--Lua/LuaJIT/Luau/(Untested) Computercraft/OpenComputers- compatible.
--This file is licensed under the Lesser GNU General Public License version 3 or later.
local tableremove,tableinsert,tablemove,gmatch,unpack = table.remove,table.insert,table.move,string.gmatch,(unpack or table.unpack)
local macros = {
	["!"] = function(front,rear,env) --Arity-conscious apply:
		--Given rear [.. F Z] , pops F, Z, Z elements in .. , and pushes all in F(..) to rear. 
		local Z,F = tableremove(rear),tableremove(rear)
		local ARGS = {}
		for I = Z,1,-1 do
			ARGS[I] = tableremove(rear) end
		local R = {F(unpack(ARGS))}
		tablemove({F(unpack(ARGS))},1,#ARGS,#rear+1,rear) end,
	["DEFV#"] = function(front,rear,env) --Define variable:
		--Define a variable of name (pop front) with value (pop rear).
		env[tableremove(front)]=tableremove(rear) end,
	["DEFM#"] = function(front,rear,env) --Define macro without arguments:
		--[DEFM# SYMBOLNAME SYMBOLEND .. SYMBOLEND]
		--will define a macro SYMBOLNAME that when called will result in .. being pushed to rear.
		local N,E = tableremove(front),tableremove(front) 
		local R = "" --Macro source.
		local C = tableremove(front)
		while C and C~=E do
			R = R .. C .. " " 
			C=tableremove(front) end
		local feval = env.feval
		env.macros[N] = function(front2,rear2,env2)  feval(R,env2,nil,rear2) end
		end,
		}
local stdenv = _ENV or getfenv(1) --TODO: Platform compatibility assignment through _VERSION.
--Arithmetic.
function sum(s,v,...) if (v) then return sum(s+v, ...) else return s end end
function dif(s,v,...) if (v) then return dif(s-v, ...) else return s end end
function mul(s,v,...) if (v) then return mul(s*v, ...) else return s end end
function divraw(s,v,...) if (v) then return s/mul(v, ...) else return s end end
function div(s,v,...) if (v) then return s/mul(v, ...) else return 1/s end end

stdenv["+"],stdenv["-"],stdenv["*"],stdenv["/"],stdenv["div"],stdenv["macros"] = sum,dif,mul,div,divraw, macros
--The meat of this file.
local function feval(str,env,front,rear)
	local env,parsed,tokens,n,rear,front = env or stdenv or {macros}, gmatch(str,'[^ ]+'),{},1,rear or {},front or {}
	local macros = env.macros
	for token in parsed do
		tokens[n]=token
	        n = n+1 end
	parsed = nil
	for tokeni = #front+1,#front + #tokens do
		front[tokeni] = tableremove(tokens) end --Reverse.
	tokens = nil
	for tokeni = 1,#front do
		local token = tableremove(front)
		local m = macros[token]
		if not m then
			rear[#rear+1] = env[token] or tonumber(token)
		else m(front,rear,env) end end 
	return rear end
local function repl(inputmethod,outputmethod,env)
	repeat local s = inputmethod()
		local res,ret = pcall(feval,s,env)
		outputmethod((res and "=< " or "!< ") , ret) until s == "!<EXIT" end
stdenv.feval = feval
return {eval=feval,repl=repl,macros=macros,stdenv=stdenv}
----merge repl----
local function repl_input() 
 io.write'=>' return io.read() end
local function repl_output(q,s)
 io.write(q) print((unpack or table.unpack)(s)) end
felth.repl(repl_input, repl_output)